using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.Diagnostics;
using Microsoft.Xna.Framework.Input.Touch;

namespace WindowsPhoneGameLibrary1
{
    /// <summary>
    /// 这是一个实现 IUpdateable 的游戏组件。
    /// </summary>
    public class ScreenManager : DrawableGameComponent
    {
        public Camera2D Camera;
        public ContentManager ContentManager;

        /// <summary>
        ///所有用到的文字资源 
        /// </summary>
        public SpriteFonts SpriteFonts;

        /// <summary>
        /// 是否启用Trace,如果为True,会在窗口里列出所有更新的screen列表。If true, the manager prints out a list of all the screens
        /// each time it is updated. This can be useful for making sure
        /// everything is being added and removed at the right times.
        /// </summary>
        public bool TraceEnabled;
        private Texture2D blankTexture;
        private InputHelper input = new InputHelper();
        private bool isInitialized;

        private List<gs> screens = new List<gs>();
        private List<gs> screensToUpdate = new List<gs>();

        private SpriteBatch spriteBatch;
        private List<RenderTarget2D> transitions = new List<RenderTarget2D>();

        public ScreenManager(Game game)
            : base(game)
        {
            // we don't assume the game wants to read them.
            TouchPanel.EnabledGestures = GestureType.None;
            ContentManager = game.Content;
            ContentManager.RootDirectory = "Content";
            // TODO: 在此处构造任何子组件
        }

        /// <summary>
        public SpriteBatch SpriteBatch
        {
            get { return spriteBatch; }
        }

        /// <summary>
        ///初始化ContentManager对象
        /// </summary>
        public override void Initialize()
        {
            SpriteFonts = new SpriteFonts(ContentManager);

            base.Initialize();

            isInitialized = true;
        }

        public void ResetTargets()
        {
            transitions.Clear();
        }

        /// <summary>
        ///加载游戏资源
        /// </summary>
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            blankTexture = ContentManager.Load<Texture2D>("Common/blank");
            Camera = new Camera2D(GraphicsDevice);
            // 让每个场景加载所用的资源
            foreach (gs screen in screens)
            {
                screen.LoadContent();
            }
        }

        /// <summary>
        /// 卸载所用的游戏资源
        /// </summary>
        protected override void UnloadContent()
        {
            // Tell each of the screens to unload their content.
            foreach (gs screen in screens)
            {
                screen.UnloadContent();
            }
        }

        /// <summary>
        /// 让每个场景执行update操作，执行游戏逻辑
        /// </summary>
        public override void Update(GameTime gameTime)
        {
            // Read the keyboard and gamepad.
            input.Update();

            // Update the camera
            Camera.Update();

            // Make a copy of the master screen list, to avoid confusion if
            // the process of updating one screen adds or removes others.
            screensToUpdate.Clear();

            foreach (gs screen in screens)
                screensToUpdate.Add(screen);

            bool otherScreenHasFocus = !Game.IsActive;
            bool coveredByOtherScreen = false;

            // Loop as long as there are screens waiting to be updated.
            while (screensToUpdate.Count > 0)
            {
                // Pop the topmost screen off the waiting list.
                gs screen = screensToUpdate[screensToUpdate.Count - 1];

                screensToUpdate.RemoveAt(screensToUpdate.Count - 1);

                // Update the screen.
                screen.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

                if (screen.ScreenState == ScreenState.TransitionOn ||
                    screen.ScreenState == ScreenState.Active)
                {
                    // If this is the first active screen we came across,
                    // give it a chance to handle input.
                    if (!otherScreenHasFocus)
                    {
                        screen.HandleInput(input);
                        otherScreenHasFocus = true;
                    }
                    // If this is an active non-popup, inform any subsequent
                    // screens that they are covered by it.
                    if (!screen.IsPopup)
                        coveredByOtherScreen = true;
                }
            }

            // Print debug trace?
            if (TraceEnabled)
                TraceScreens();
        }

        /// <summary>
        /// Prints a list of all the screens, for debugging.
        /// </summary>
        private void TraceScreens()
        {
            List<string> screenNames = new List<string>();

            foreach (gs screen in screens)
                screenNames.Add(screen.GetType().Name);

            Debug.WriteLine(string.Join(", ", screenNames.ToArray()));
        }

        /// <summary>
        ///开始渲染每个场景
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            int transitionCount = 0;
            foreach (gs screen in screens)
            {
                if (screen.ScreenState == ScreenState.TransitionOn ||
                    screen.ScreenState == ScreenState.TransitionOff)
                {
                    ++transitionCount;
                    if (transitions.Count < transitionCount)
                    {
                        PresentationParameters _pp = GraphicsDevice.PresentationParameters;
                        transitions.Add(new RenderTarget2D(GraphicsDevice, _pp.BackBufferWidth, _pp.BackBufferHeight,
                                                            false,
                                                            SurfaceFormat.Color, DepthFormat.Depth24Stencil8, _pp.MultiSampleCount,
                                                            RenderTargetUsage.DiscardContents));
                    }
                    GraphicsDevice.SetRenderTarget(transitions[transitionCount - 1]);
                    GraphicsDevice.Clear(Color.Transparent);
                    screen.Draw(gameTime);
                    GraphicsDevice.SetRenderTarget(null);
                }
            }

            GraphicsDevice.Clear(Color.Black);

            transitionCount = 0;
            foreach (gs screen in screens)
            {
                if (screen.ScreenState == ScreenState.Hidden)
                    continue;

                if (screen.ScreenState == ScreenState.TransitionOn ||
                    screen.ScreenState == ScreenState.TransitionOff)
                {

                    spriteBatch.Begin();
                    spriteBatch.Draw(transitions[transitionCount], Vector2.Zero, Color.White * screen.TransitionAlpha);
                    spriteBatch.End();


                    ++transitionCount;
                }
                else
                {
                    screen.Draw(gameTime);
                }
            }
        }

        /// <summary>
        /// 添加一个新的场景到管理器中
        /// </summary>
        public void AddScreen(gs screen, PlayerIndex? controllingPlayer)
        {
            screen.ControllingPlayer = controllingPlayer;
            screen.ScreenManager = this;
            screen.IsExiting = false;

            // If we have a graphics device, tell the screen to load content.
            if (isInitialized)
            {
                screen.LoadContent();
            }

            screens.Add(screen);

            // update the TouchPanel to respond to gestures this screen is interested in
            TouchPanel.EnabledGestures = screen.EnabledGestures;

            screen.FirstRun = false;
        }

        /// <summary>
        /// 移除制定的场景。不过通常调用gs.ExitScreen来代替这个方法。这样比直接调用RemoveScreen好，中间有一个过渡过程。 
        /// </summary>
        public void RemoveScreen(gs screen)
        {
            // If we have a graphics device, tell the screen to unload content.
            if (isInitialized)
            {
                screen.UnloadContent();
            }

            screens.Remove(screen);
            screensToUpdate.Remove(screen);

            // if there is a screen still in the manager, update TouchPanel
            // to respond to gestures that screen is interested in.
            if (screens.Count > 0)
            {
                TouchPanel.EnabledGestures = screens[screens.Count - 1].EnabledGestures;
            }
        }

        /// <summary>
        /// Expose an array holding all the screens. We return a copy rather
        /// than the real master list, because screens should only ever be added
        /// or removed using the AddScreen and RemoveScreen methods.
        /// </summary>
        public gs[] GetScreens()
        {
            return screens.ToArray();
        }

        /// <summary>
        ///绘制一个黑色半透明的背景，用来表示场景的渐进淡出,或者充当一个弹出窗口的背景色。 
        /// </summary>
        public void FadeBackBufferToBlack(float alpha)
        {
            Viewport viewport = GraphicsDevice.Viewport;

            spriteBatch.Begin();

            spriteBatch.Draw(blankTexture,
                              new Rectangle(0, 0, viewport.Width, viewport.Height),
                              Color.Black * alpha);

            spriteBatch.End();
        }

        public Vector2 translate { get; set; }
    }
}

